#include <ez80F91.h>
#include <stdio.h>

#include "ZSysgen.h"
#include "ZTypes.h"
#include "ZThread.h"
#include "ZDevice.h"
#include "i2c.h"

#include "temperature.h"
#include "Types.h"
#include "sleep.h"

/* i2c bus master device */
RZK_DEVICE_CB_t *i2c;

/*
 * Initialize the digital temperature thermometer (DS1621)
 * Should be called on startup
 *
 * Params:
 *		none
 *
 * Returns:
 *		SUCCESS when the digital thermometer successfully initializes
 *		GENERAL_ERROR when an error occurs initializing
 */
error_t temperatureInit()
{
	RZK_STATUS_t status;
	INT8 mode = I2C_MASTER;
	INT8 slvAddr = 0x90;
	UINT8 subAddr = 0x00;
	UINT8 subAddrLen = 1;
	UINT8 busSpeed = 0x05;
	INT8 data[2];
	INT len;

	/* initialize i2c */
    AddI2c();
    i2c = RZKDevOpen((RZK_DEV_NAME_t *)"I2C", &mode);

	if (i2c == NULL)
		return GENERAL_ERROR;

	/* set the save address to be that of the temp IC (0x90) */
	status = RZKDevIOCTL(i2c, I2C_SET_SLAVE_ADDR, &slvAddr, NULL);
	if (status != I2CERR_SUCCESS)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}
	/* set the speed to be 160KHz */
	status = RZKDevIOCTL(i2c, I2C_SET_SPEED, &busSpeed, NULL);
	if (status != I2CERR_SUCCESS)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}
	/* set the sub address length to 1 */
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_LEN, &subAddrLen, NULL);
	if (status != I2CERR_SUCCESS)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}

	/* read configuration register */
	subAddr = 0xAC;
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_USED, &subAddr, NULL);
	if (status != I2CERR_SUCCESS)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}
	len = RZKDevRead(i2c, data, 1);
	if (len != 1)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}

	/* update configuration if not correct */
	if ((data[0] & 0x03) != 0x02)
	{
		/* set continuous conversion */
		subAddr = 0xAC;
		status = RZKDevIOCTL(i2c, I2C_SUBADDR_USED, &subAddr, NULL);
		if (status != I2CERR_SUCCESS)
		{
			RZKDevClose(i2c);
			return GENERAL_ERROR;
		}
		data[0] = 0x02;
		if (RZKDevWrite(i2c, data, 1) != 1)
		{
			RZKDevClose(i2c);
			return GENERAL_ERROR;
		}
	}

	/* start conversion */
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_NOT_USED, NULL, NULL);
	if (status != I2CERR_SUCCESS)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}
	data[0] = 0xEE;
	if (RZKDevWrite(i2c, data, 1) != 1)
	{
		RZKDevClose(i2c);
		return GENERAL_ERROR;
	}

	/* wait 750 ms to ensure the first temp read succeeds */
	sleep(750);

	return SUCCESS;
}

/*
 * Reads the current temperature and copies it into the variable passed in
 *
 * Params:
 *		units - FAHRENHEIT or CELSIUS, determines units for the output
 *		currTemp - Outputs the current temperature (in the units passed in)
 *
 * Returns:
 *		SUCCESS when the temperature can be read
 *		GENERAL_ERROR when an error occurs reading the temperature
 */
error_t temperatureRead(temp_unit_t units, temp_t offset, float *currTemp)
{
	RZK_STATUS_t status;
	INT8 temp_read[2];
	INT8 count_per_c;
	INT8 count_remain;
	UINT8 subAddr;


	/* read the current temperature */
	subAddr = 0xAA;
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_USED, &subAddr, NULL);
	if (status != I2CERR_SUCCESS)
		return GENERAL_ERROR;

	if (RZKDevRead(i2c, temp_read, 2) == 2)
	{
		/* check for invalid whole degree value */
		if ((temp_read[0] > (INT8)125) ||
			(temp_read[0] < (INT8)-55))
		{
			return GENERAL_ERROR;
		}

		/* check for invalid 1/2 degree value */
		if ((temp_read[1] != (INT8)0x00) &&
			(temp_read[1] != (INT8)0x80))
		{
			return GENERAL_ERROR;
		}
	}
	else
	{
		return GENERAL_ERROR;
	}

	/* get the read counter */
	subAddr = 0xA8;
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_USED, &subAddr, NULL);
	if (status != I2CERR_SUCCESS)
		return GENERAL_ERROR;
	if (RZKDevRead(i2c, &count_remain, 1) != 1)
		return GENERAL_ERROR;

	/* get the read slope */
	subAddr = 0xA9;
	status = RZKDevIOCTL(i2c, I2C_SUBADDR_USED, &subAddr, NULL);
	if (status != I2CERR_SUCCESS)
		return GENERAL_ERROR;
	if (RZKDevRead(i2c, &count_per_c, 1) != 1)
		return GENERAL_ERROR;

	/* calculate the temperature in celcius */
	*currTemp = (float)temp_read[0] - (float)0.25;
	*currTemp += ((float)count_per_c - (float)count_remain)/(float)count_per_c;

	/* convert to fahrenheit if necessary */
	if (units == FAHRENHEIT)
	{
		*currTemp *= (float)1.8;
		*currTemp += (float)32;
	}

	*currTemp += (float) offset;

#if _DEBUG
	printf("TEMP: %f\r\n", *currTemp);
#endif

	return SUCCESS;
}
